今日文章目錄
- 前言
- useMemo()
- 實作紀錄
- 參考資料
- 後續
今天要練習 useMemo(),不過爬了很多文,覺得還無法好好消化,這篇主要紀錄一些我找到的資料筆記,還有練習的過程。開始吧!
昨天我們在切換頁面的時候,透過Provider value props把{state, setState}傳下去,讓子層可以改值。
// Provider 傳值與方法:
function App() {
const [themsState, setThemeState] = useState(theme.light);
return (
<ThemeContext.Provider value={{ themsState, setThemeState }}>
...
</ThemeContext.Provider>
);
}
export default App;
function CategoryList(props) {
const { themsState, setThemeState } = useContext(ThemeContext);
return (...)
}
console.log()看一下,會發現:Provider傳什麼,useContext()就會回傳什麼(就是最新值)。
官方文件有提到以下情況:
我想確定目前寫法:<Context.Provider value ={{state, setState}}></Context.Provider>會不會造成上述的問題。搜了一輪資料,決定用useMemo inside Context API - React的方法來測試看看。
為了做個測試,我分別在父層ToDoPage,子層CategoryList TodoList component內加入 console.log(),來確認一下使用useMemo()與沒有使用useMemo()的差異。
ToDoPage點擊按鈕更新值時,Provider props value 是否會重新建立,導致子層 CategoryList ToDoList re-render?CategoryList 父層加入 ThemeContext.Provider value props :useMemo(),當 dependency改變時,才更新回傳值。ToDoList 父層加入 ThemeContext.Provider value props :{ themsState, setThemeState }

export default function ToDoPage() {
const [forceRender, setForceRender] = useState(false);
const [themsState, setThemeState] = useState(theme.light);
const themeContextProvider = useMemo(() => (
{ themsState, setThemeState }), [themsState, setThemeState]
);
return (
<>
{console.log('hey! I am in ToDoPage.')}
<MainLayout
menu={(
<ThemeContext.Provider value={themeContextProvider}>
<CategoryList />
</ThemeContext.Provider>
)}
content={(
<ThemeContext.Provider value={{ themsState, setThemeState }}>
<ToDoList />
</ThemeContext.Provider>
)}
/>
<Button onClick={() => setForceRender(!forceRender)}>Rerender Parent</Button>
</>
);
}
顯示效果:
ToDoList 或 CategoryList 切換 theme,更新ThemeContext.Provider值。
ToDoPage 點擊按鈕: 觸發 ToDoPage CategoryList ToDoList re-render。
疑?看不出來 useMemo() 的效果![]()

export default memo(CategoryList);
export default memo(ToDoList);
顯示效果:
ToDoList 或 CategoryList 切換 theme,更新ThemeContext.Provider值。
ToDoPage 點擊按鈕: 觸發 ToDoPage ToDoList re-render。CategoryList 沒有。
呼~終於有點收穫...
目前看起來的狀況:
測試A:父層狀態改變,子層re-render。
測試B:父層狀態改變,透過memo()比對CategoryList ToDoList,根本沒有props,所以不受父層狀態改變影響,唯一帶來改變的是ToDoList的ThemeContext.Provider value={{ themsState, setThemeState }},每次都重新建立。
不過我應該把 console.log() 放一個在 useMemo()比較準才對..
useMemo 小百科:
useMemo(() => computeExpensiveValue(a, b), [a, b]);
- 為了解決當元件本身改變狀態 re-render,避免元件內無關的邏輯重複渲染的效能問題。
- 用途:當dependency改變,才會執行
computeExpensiveValue(a, b)重新計算,回傳一個 memoized 的值。- 參數:
computeExpensiveValue(a, b): 一function,回傳值會讓React記著,在dependency沒改變的情況下,會一直沿用該回傳值。[a, b]: dependency。
memo 小百科:
memo(MyComponent, areEqual):
React 渲染機制,只要父層state改變,不論子層接收的props值是否有改變,子層一律強迫 re-render。memo()是為了解決子層接收的props導致重複渲染的效能問題。
- 用途:比對 更新前後
props差異,沒有改變,會跳過這次 re-render。- 參數:
>MyComponent: 作用元件
>areEqual *(optional)*: 客制function。memo()比對方式shallowly compare complex objects in the props object,如果要做更深層的比對,可以自己寫。- If your function component wrapped in React.memo has a useState, useReducer or useContext Hook in its implementation, it will still rerender when state or context change. - 節錄React 官網。
Object.is(value1, value2)
React uses the
Object.is comparison algorithm.
哇~真的把30天撐完了,好感動喔![]()
10天React練習讓我有機會重新再回來看React 文件,我記得我剛開始接觸的時候,真的是有看沒有懂...目前寫了半年多,回來看文件會發現以前看不懂的,現在漸漸能理解它的意思,還有很多需要再練習,但覺得滿足。感謝鐵人賽!
這10天只有寫到一小部分,回頭看自己的文章,有些知識漏洞。之後會繼續補齊 use系列,不會一天一po,等我練到有點心得再繼續跟大家分享,恭喜各位鐵人完賽,下次見囉!![]()